import struct
from codecs import StreamReader
import os
from . import Importer
import mathutils

def read_float32(f):
    return round(struct.unpack('f', f.read(4))[0], 4)


def read_float16(f):
    return round(struct.unpack('f', f.read(2))[0], 4)


def read_int32(f):
    return int.from_bytes(f.read(4), 'little')


def read_int16(f):
    return int.from_bytes(f.read(2), 'little')

class PartObj():
    def __init__(self):
        super().__init__()
        self.name = ''
        self.vertices = []
        self.uvs = []
        self.indices = []
        self.uvindices = []
        self.normals = []
        self.child = []
        self.coord = []
        self.scale_base = []
        self.scale_what = []
        self.rotation = []

        self.bbmax = []
        self.bbmin = []

def read_dummy(f):
    Obj = PartObj()
    id = read_int16(f)
    namecount = read_int32(f)
    name = f.read(namecount*2).decode('utf-16le')
    print(name)
    Obj.name = name
    NumberOfChild = read_int32(f)
    for i in range(NumberOfChild):
        flag = f.read(6)
        if flag == b'\xAA\x47\x46\x04\x2A\x19':
            if NumberOfChild == 1:
                Obj = read_mesh(f)
                Obj.name = name
            else:
                Obj.child.append(read_mesh(f))
        elif flag == b'\xAA\x47\x3C\x03\x07\x0E':
            Obj.child.append(read_dummy(f))
    
    scale_x = mathutils.Vector((read_float32(f), read_float32(f), read_float32(f)))
    scale_y = mathutils.Vector((read_float32(f), read_float32(f), read_float32(f)))
    scale_z = mathutils.Vector((read_float32(f), read_float32(f), read_float32(f)))
    Obj.scale_base = [scale_x,scale_y,scale_z]
    Obj.coord = [read_float32(f), read_float32(f), read_float32(f)]
    Obj.scale_what = [read_float32(f), read_float32(f), read_float32(f)]
    Obj.bbmin = [read_float32(f), read_float32(f), read_float32(f)]
    Obj.bbmax = [read_float32(f), read_float32(f), read_float32(f)]
    f.read(0x2E)
    return Obj

def read_mesh(f):
    Obj = PartObj()
    id = read_int16(f)
    namecount = read_int32(f)
    name = f.read(namecount*2).decode('utf-16le')
    f.read(4)
    scale_x = mathutils.Vector((read_float32(f), read_float32(f), read_float32(f)))
    scale_y = mathutils.Vector((read_float32(f), read_float32(f), read_float32(f)))
    scale_z = mathutils.Vector((read_float32(f), read_float32(f), read_float32(f)))
    Obj.scale_base = [scale_x,scale_y,scale_z]
    Obj.coord = [read_float32(f), read_float32(f), read_float32(f)]
    Obj.scale_what = [read_float32(f), read_float32(f), read_float32(f)]
    Obj.bbmin = [read_float32(f), read_float32(f), read_float32(f)]
    Obj.bbmax = [read_float32(f), read_float32(f), read_float32(f)]
    f.read(0x32)
    print(name)
    if f.read(2) == b'\xAA\x27':
        f.read(2)

        vertices = []
        uvs = []
        Indices = []
        uvindices = []
        normals = []
        normalindices = []

        print(f'vertices: {f.tell()}')
        verticescount = read_int32(f)
        for i in range(0, verticescount, 1):
            vertices.append([read_float32(f), read_float32(f), read_float32(f)])

        print(f'normals: {f.tell()}')
        normalcount = read_int32(f)
        for i in range(0, normalcount, 1):
            normals.append([read_float32(f), read_float32(f), read_float32(f)])
        
        print(f'uvs: {f.tell()}')
        uvcount = read_int32(f)
        f.read(4)
        l = []
        for i in range(0, uvcount, 1):
            x = round(read_float32(f), 4)
            y = round(1-read_float32(f), 4)
            uvs.append([x, y])
            l.append([read_int16(f), read_int16(f)])
        
        f.seek(-4, 1)

        StructsLength = read_int32(f)
        StructsOffset = f.tell()

        f.seek(StructsOffset)
        for i in range(0, StructsLength, 1):
            one = read_int16(f)
            two = read_int16(f)
            three = read_int16(f)
            uvindices.append([one, two, three])
            f.read(14)


        f.seek(StructsOffset+12)
        for i in range(0, StructsLength, 1):
            one = read_int16(f)+1
            two = read_int16(f)+1
            three = read_int16(f)+1
            Indices.append([one, two, three])
            f.read(14)

        f.seek(-12, 1)

        print(f'end: {f.tell()}')

        Obj.name = name
        Obj.vertices = vertices
        Obj.uvs = uvs
        Obj.indices = Indices
        Obj.uvindices = uvindices
        Obj.normals = normals
        Obj.normalindice = normalindices
    return Obj



def read_kart(filepath):
    f = open(filepath, 'rb')
    f.seek(0xC)
    NumOfObjs = read_int32(f)
    Objs = []
    for i in range(NumOfObjs):
        flag = f.read(6)
        if flag == b'\xAA\x47\x46\x04\x2A\x19':
            Objs.append(read_mesh(f))
        elif flag == b'\xAA\x47\x3C\x03\x07\x0E':
            Objs.append(read_dummy(f))
                
    for obj in Objs:
        Importer.write_obj(obj, False)